#include "MiniBSplineSurfaceHandler.h"

MiniBSplineSurfaceHandler::MiniBSplineSurfaceHandler(MiniObject *obj)
    : MiniHandler(obj)
{
    UpdateHandler();
}

float MiniBSplineSurfaceHandler::CheckCollision(QPointF pos, QMatrix4x4 projection)
{
    // 之后增加选中程序
    Q_UNUSED(pos)
    Q_UNUSED(projection)
    return 1;
}

void MiniBSplineSurfaceHandler::ChangeVertex(Vector3f dv)
{
    Q_UNUSED(dv)
}

void MiniBSplineSurfaceHandler::UpdateHandler()
{
    InitHandler();
    LoadSpline();
    LoadIsopara();
    LoadCpts();
}

void MiniBSplineSurfaceHandler::LoadSpline()
{
    // 转化为 B 样条曲面类型
    MiniBSplineSurface *spline = (MiniBSplineSurface*)m_object;

    Real bu = spline->GetUBegin();
    Real eu = spline->GetUEnd();
    Real bv = spline->GetVBegin();
    Real ev = spline->GetVEnd();
    float* vertices = new float[100*100*6];
    unsigned int* indices = new unsigned int[99*99*6];
    for (int i = 0; i < 99; i++)
    {
        for (int j = 0; j < 99; j++)
        {
            // 四边形分割成两个三角形
            int k = i * 99 + j;
            indices[k * 6 + 0] = i * 100 + j;
            indices[k * 6 + 1] = i * 100 + j + 1;
            indices[k * 6 + 2] = (i + 1) * 100 + j;
            indices[k * 6 + 3] = i * 100 + j + 1;
            indices[k * 6 + 4] = (i + 1) * 100 + j + 1;
            indices[k * 6 + 5] = (i + 1) * 100 + j;
        }
    }

    for (int i = 0; i < 100; i++)
    {
        for (int j = 0; j < 100; j++)
        {
            int k = i * 100 + j;

            float u = bu + (eu - bu) / 99 * i;
            float v = bv + (ev - bv) / 99 * j;
            MiniArray2D<Vector3f> DS = spline->SurfaceDerivPoint(1, u, v);
            vertices[k * 6 + 0] = DS[0][0].x();
            vertices[k * 6 + 1] = DS[0][0].y();
            vertices[k * 6 + 2] = DS[0][0].z();

            Vector3f n = cross(DS[1][0], DS[0][1]);
            n = normalize(n);
            vertices[k * 6 + 3] = n.x();
            vertices[k * 6 + 4] = n.y();
            vertices[k * 6 + 5] = n.z();
        }
    }

    // 储存数据
    m_countIndices.push_back(99*99*6);
    m_countVertices.push_back(100*100*2);
    m_vertices.push_back(vertices);
    m_indices.push_back(indices);
    m_modes.push_back(GL_TRIANGLES);
    m_color.push_back(m_basisColor);
    m_lineWidth.push_back(1);
}

void MiniBSplineSurfaceHandler::LoadCpts()
{
    // 转化为 B 样条类型
    MiniBSplineSurface *spline = (MiniBSplineSurface*)m_object;

    // 推入控制点
    int Nu = spline->GetUPointsNum();
    int Nv = spline->GetVPointsNum();
    const MiniArray2D<Vector3f> &cpts = spline->GetPoints();
    float* vertices = new float[Nu * Nv * 3];
    unsigned int* indices = new unsigned int[Nu * Nv];
    for (int i = 0; i < Nu; i++)
    {
        for (int j = 0; j < Nv; j++)
        {
            int k = i * Nv + j;
            indices[k] = k;
            vertices[k * 3 + 0] = cpts[i][j].x();
            vertices[k * 3 + 1] = cpts[i][j].y();
            vertices[k * 3 + 2] = cpts[i][j].z();
        }
    }

    // 储存数据
    m_countIndices.push_back(Nu * Nv);
    m_countVertices.push_back(Nu * Nv);
    m_vertices.push_back(vertices);
    m_indices.push_back(indices);
    m_modes.push_back(GL_POINTS);
    m_color.push_back({0.6, 0.6, 0.6});
    m_lineWidth.push_back(1);
}

void MiniBSplineSurfaceHandler::LoadIsopara()
{
    MiniBSplineSurface *spline = (MiniBSplineSurface*)m_object;
    MiniArray<Real> uknots = spline->GetUKnots();
    MiniArray<Real> vknots = spline->GetVKnots();

    // 获得需要计算的节点索引范围
    int bui = spline->GetUDegree();
    int eui = uknots.size()- bui - 1;
    int bvi = spline->GetVDegree();
    int evi = vknots.size()- bvi - 1;

    // 获得有效区间范围
    Real bu = spline->GetUBegin();
    Real eu = spline->GetUEnd();
    Real bv = spline->GetVBegin();
    Real ev = spline->GetVEnd();

    // 计算 u 等参线
    for (int i = bui; i < eui + 1; i++)
    {
        // 每条等参线都要独立保存
        float* vertices = new float[100 * 3];
        unsigned int* indices = new unsigned int[100];

        float u = uknots[i];
        for (int j = 0; j < 100; j++)
        {
            float v = bv + (ev - bv) / 99 * j;
            Vector3f S = spline->SurfacePoint(u, v);

            indices[j] = j;
            vertices[j * 3 + 0] = S.x();
            vertices[j * 3 + 1] = S.y();
            vertices[j * 3 + 2] = S.z();
        }

        // 储存数据
        m_countIndices.push_back(100);
        m_countVertices.push_back(100);
        m_vertices.push_back(vertices);
        m_indices.push_back(indices);
        m_modes.push_back(GL_LINE_STRIP);
        m_color.push_back({0, 0, 0});
        m_lineWidth.push_back(1);
    }

    // 计算 v 等参线
    for (int i = bvi; i < evi + 1; i++)
    {
        // 每条等参线都要独立保存
        float* vertices = new float[100 * 3];
        unsigned int* indices = new unsigned int[100];

        float v = vknots[i];
        for (int j = 0; j < 100; j++)
        {
            float u = bu + (eu - bu) / 99 * j;
            Vector3f S = spline->SurfacePoint(u, v);

            indices[j] = j;
            vertices[j * 3 + 0] = S.x();
            vertices[j * 3 + 1] = S.y();
            vertices[j * 3 + 2] = S.z();
        }

        // 储存数据
        m_countIndices.push_back(100);
        m_countVertices.push_back(100);
        m_vertices.push_back(vertices);
        m_indices.push_back(indices);
        m_modes.push_back(GL_LINE_STRIP);
        m_color.push_back({0, 0, 0});
        m_lineWidth.push_back(1);
    }
}
